using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;

namespace Bamboo.Core.Common.Storage
{
    public class FTPStorageProvider: StorageProvider
    {

        private string m_username;
        private string m_password;
        private bool m_usePassive;
        private bool m_enableSsl;
        private string m_path;
        private bool m_auth;
        private string m_destinationDirectory;

        public string DestinationDirectory
        {
            get { return m_destinationDirectory; }
            set { m_destinationDirectory = value; }
        }

        public bool Auth
        {
            get { return m_auth; }
            set { m_auth = value; }
        }


        public string Path
        {
            get { return m_path; }
            set { m_path = value; }
        }

        public bool EnableSsl
        {
            get { return m_enableSsl; }
            set { m_enableSsl = value; }
        }

        public bool PassiveMode
        {
            get { return m_usePassive; }
            set { m_usePassive = value; }
        }

        public string Password
        {
            get { return m_password; }
            set { m_password = value; }
        }

        public string Username
        {
            get { return m_username; }
            set { m_username = value; }
        }

        private ICredentials GetCredentials()
        {
            if (m_auth)
                return new NetworkCredential(m_username, m_password);
            else
                return new CredentialCache();
        }
        private Uri GetUri(string subPath)
        {
            return new Uri(m_path + subPath);
        }
        private static string[] ReadLines(Stream src)
        {
            List<string> lines = new List<string>();
            StreamReader r = new StreamReader(src);
            while (!r.EndOfStream)
            {
                lines.Add(r.ReadLine());
            }
            return lines.ToArray();
        }
        private void CopyStream(Stream src, Stream dest)
        {
            try
            {
                int bytesRead;
                byte[] buffer = new byte[1024];

                do
                {
                    bytesRead = src.Read(buffer, 0, buffer.Length);
                    if (bytesRead > 1) dest.Write(buffer, 0, bytesRead);
                } while (bytesRead == buffer.Length);
                dest.Flush();
            }
            catch (Exception err)
            {
                log4net.Util.LogLog.Error(err.Message);
                Console.WriteLine(err.Message);
            }
        }



        public override List<string> List(string path)
        {
            List<string> list = new List<string>();

            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(GetUri(path));
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
                request.KeepAlive = false;
                request.UseBinary = true;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                string[] lines = ReadLines(response.GetResponseStream());
                foreach (string line in lines)
                {
                    string[] arguments = line.Split(new char[] { '\x20', '\t' }, 4, StringSplitOptions.RemoveEmptyEntries);
                    bool isFolder = arguments[2].Equals("<DIR>");
                    if (!isFolder)
                    {
                        list.Add(arguments[3]);
                    }
                }
            }
            catch { }

            return list;
        }

        public override List<string> List(string path, string fillter)
        {
            List<string> list = new List<string>();
            try
            {
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(GetUri(path));
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
                request.KeepAlive = false;
                request.UseBinary = true;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                string[] lines = ReadLines(response.GetResponseStream());
                foreach (string line in lines)
                {
                    string[] arguments = line.Split(new char[] { '\x20', '\t' }, 4, StringSplitOptions.RemoveEmptyEntries);
                    bool isFolder = arguments[2].Equals("<DIR>");
                    if (!isFolder)
                    {
                        if (fillter.IndexOf(System.IO.Path.GetExtension(arguments[3])) >= 0)
                            list.Add(arguments[3]);
                    }
                }
            }
            catch { }

            return list;
        }

        public override bool Upload(string src, string dest)
        {
            try
            {
                Uri remoteUri = GetUri(dest);
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(remoteUri);
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.UploadFile;

                request.KeepAlive = false;
                request.UseBinary = true;


                Stream srcStream = File.OpenRead(src);
                Stream destStream = request.GetRequestStream();
                CopyStream(srcStream, destStream);

                srcStream.Close();
                destStream.Close();
                try
                {
                    WebResponse response = request.GetResponse();
                    response.Close();
                }
                catch (Exception ex)
                {
                    log4net.Util.LogLog.Error("error uploading the file :" + ex.Message);
                    Console.WriteLine(ex.Message);
                }
            }
            catch (Exception err)
            {
                log4net.Util.LogLog.Error("error uploading the file :" + err.Message);
                Console.WriteLine(err.Message);
                return false;
            }

            return true;
        }

        public override bool Download(string src, string dest)
        {
            try
            {
                Uri remoteUri = GetUri(System.IO.Path.GetFileName(src));
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(remoteUri);
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.DownloadFile;

                request.KeepAlive = false;
                request.UseBinary = true;

                WebResponse response = request.GetResponse();

                Stream srcStream = response.GetResponseStream();
                Stream destStream = File.OpenWrite(dest);
                CopyStream(srcStream, destStream);

                srcStream.Close();
                destStream.Close();
                response.Close();
            }
            catch
            {
                return false;
            }
            return true;
        }

        public override Stream Download(string src)
        {
            try
            {
                Uri remoteUri = GetUri(src.ToLower());
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(remoteUri);
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.DownloadFile;

                request.KeepAlive = false;
                request.UseBinary = true;

                WebResponse response = request.GetResponse();

                return response.GetResponseStream();
            }
            catch
            {
                //log4net.Util.LogLog.Error("Error in Function Download, in FtpStorgaeProvider.cs " + err.Message);
            }
            return null;
        }

        public override bool MakeDir(string path)
        {
            try
            {
                Uri remote = GetUri(path);
                Console.WriteLine("Remote: " + remote.AbsoluteUri);
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(remote);
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.MakeDirectory;
                request.KeepAlive = false;
                request.UseBinary = true;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Console.WriteLine("MakeDir status: {0}", response.StatusDescription);
                response.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
            return true;

        }

        public override string GetDestinationDirectory()
        {
            return string.Empty;
        }

        public override bool CanRead()
        {
            return true;
        }

        public override bool CanWrite()
        {
            return true;
        }

        public override bool CanList()
        {
            return true;
        }

        public override bool Delete(string path)
        {
            try
            {
                Uri remote = GetUri(path);
                Console.WriteLine("Remote: " + remote.AbsoluteUri);
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(remote);
                request.UsePassive = m_usePassive;
                request.EnableSsl = m_enableSsl;
                request.Credentials = GetCredentials();
                request.Method = WebRequestMethods.Ftp.DeleteFile;
                request.KeepAlive = false;
                request.UseBinary = true;

                FtpWebResponse response = (FtpWebResponse)request.GetResponse();
                Console.WriteLine("Delete status: {0}", response.StatusDescription);
                response.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
            return true;
        }

        public override bool CanDelete()
        {
            return true;
        }
    }
}
